package pushmessage

import (
	"strconv"
	"sync"
	"time"

	"gitee.com/xbkw/vimpirture/list"
	"github.com/Allenxuxu/gev"
	"github.com/Allenxuxu/gev/connection"
)

type PushMessage struct {
	s *gev.Server

	rw   sync.RWMutex
	conn *list.List

	countRw sync.RWMutex
	counts  int64
}

func New(port string) (*PushMessage, error) {
	server := &PushMessage{}

	s, err := gev.NewServer(server, gev.Address(":"+port))
	if err != nil {
		return nil, err
	}
	server.s = s
	server.conn = list.New()

	return server, nil
}

func (o *PushMessage) OnConnect(c *connection.Connection) {
	o.countRw.Lock()
	o.counts++
	o.countRw.Unlock()

	o.rw.Lock()
	e := o.conn.PushBack(c)
	o.rw.Unlock()

	c.Set("rko", e)
}

func (o *PushMessage) OnMessage(c *connection.Connection,
	ctx interface{}, data []byte) []byte {
	out := data
	return out
}

func (o *PushMessage) OnClose(c *connection.Connection) {
	o.countRw.Lock()
	o.counts++
	o.countRw.Unlock()

	e, _ := c.Get("rko")
	o.rw.Lock()
	o.conn.Remove(e.(*list.Element))
	o.rw.Unlock()
}

func (o *PushMessage) Start() {
	o.s.RunEvery(1*time.Second, o.push)
	o.s.Start()
}

func (o *PushMessage) Stop() {
	o.s.Stop()
}

func (o *PushMessage) push() {
	o.countRw.Lock()
	counts := o.counts
	o.countRw.Unlock()

	str := "counts : " + strconv.Itoa(int(counts))

	o.rw.RLock()
	defer o.rw.RUnlock()

	e := o.conn.Front()
	for ; e != nil; e = e.Next() {
		c := e.Value.(*connection.Connection)
		c.Send([]byte(str))
	}
}
